package com.bestom.hardwaretest.activity;

import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.ScrollView;
import android.widget.Spinner;
import android.widget.TextView;
import com.bestom.hardwaretest.File.FilesManager;
import com.bestom.hardwaretest.R;
import com.bestom.hardwaretest.util.DataTurn;
import com.bestom.hardwaretest.util.ToastUtil;
import com.suke.widget.SwitchButton;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import android_serialport_api.SerialPort;

public class SerialportActivity extends BaseActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_serialport);
        initData();
        initView();
    }

    private ScrollView mScrollView;
    private TextView textView;
    private SwitchButton serialPort;
    private void initView() {
        Spinner serialSpinner = findViewById(R.id.serial_spinner);
        serialSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                mHandler.sendEmptyMessage(0);
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {

            }
        });
        Spinner portSpinner = findViewById(R.id.port_spinner);
        portSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                mHandler.sendEmptyMessage(0);
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {

            }
        });
        EditText sendEdit = findViewById(R.id.send_edit);
        textView = findViewById(R.id.textView);
        mScrollView = findViewById(R.id.scrollView);
        SwitchButton sb485 = findViewById(R.id._485);
        sb485.setOnCheckedChangeListener((view, isChecked) -> {
            if (!mFilesManager.write485(isChecked ? "1" : "0")) ToastUtil.toast("485 GPIO节点错误，请检查！");
        });
        serialPort = findViewById(R.id.serial_port);
        serialPort.setOnCheckedChangeListener((view, isChecked) -> {
            close();
            if (isChecked){
                openSerialPort((String) serialSpinner.getSelectedItem(),Integer.parseInt((String) portSpinner.getSelectedItem()));
            }
        });
        findViewById(R.id.back).setOnClickListener(v -> finish());
        findViewById(R.id.send).setOnClickListener(v -> {
            if (sb485.isChecked()) writeHexToBoard(sendEdit.getText().toString().replace(" ","").trim());
            else updateView("发送失败，请先拉高485电平");
        });
        findViewById(R.id.clear_send).setOnClickListener(v -> sendEdit.setText(""));
        findViewById(R.id.clear_receive).setOnClickListener(v -> textView.setText(""));
    }
    private FilesManager mFilesManager;
    private void initData() {
        mFilesManager = new FilesManager("");
        mDataTurn = new DataTurn();
        readThread = new ReadThread();
    }


    private DataTurn mDataTurn;
    private InputStream mInputStream;
    private OutputStream mOutputStream;
    private SerialPort mSerialPort;
    private boolean first = true;

    private void openSerialPort(String pathName, int port) {
        try {
            mSerialPort = new SerialPort(new File(pathName), port, 0);
            // 获取输入输出流
            mInputStream = mSerialPort.getInputStream();
            mOutputStream = mSerialPort.getOutputStream();

            if (first){
                first = false;
                readReturnResult();
            }
            updateView("串口打开成功");
        } catch (IOException e) {
            mHandler.sendEmptyMessage(0);
            updateView("串口打开失败");
            Log.d("SerialPortService","找不到该设备文件");
        }
    }

    public static boolean isSpecialChar(String str) {
        String regEx = "[ _`~!@#$%^&*()+=|{}':;',\\[\\].<>/?~！@#￥%……&*（）——+|{}【】‘；：”“’。，、？g-zG-Z]|\n|\r|\t";
        Pattern p = Pattern.compile(regEx);
        Matcher m = p.matcher(str);
        return m.find();
    }


    public void writeHexToBoard(String inHex) {
        if (inHex.isEmpty()) {
            updateView("内容为空，请检查");
            return;
        }
        if (mOutputStream == null){
            updateView("send:(" + inHex + ")  发送失败，未打开串口");
            return;
        }
        if (isSpecialChar(inHex)){
            updateView("send:(" + inHex + ")  发送失败，存在非十六进制字符");
            return;
        }
        byte[] bytes = mDataTurn.HexToByteArr(inHex);

        // 写入数据
        try {
            mOutputStream.write(bytes);
            mOutputStream.flush();
            updateView("send:(" + inHex + ")  发送成功");
        } catch (IOException e) {
            updateView("send:(" + inHex + ")  发送失败,流写入异常");
            e.printStackTrace();
        }
    }
    private ReadThread readThread;
    private void readReturnResult(){
        // 开启子线程，不断读取返回结果
        readThread.start();
    }

    boolean flag = true;
    private class ReadThread extends Thread {
        @Override
        public void run() {
            super.run();

            while (flag) {
                try {
                    if (mInputStream.available() <= 0) {
                        continue;
                    } else {
                        Thread.sleep(200);
                    }
                    byte[] buffer = new byte[128];
                    int size = mInputStream.read(buffer);
                    byte[] readBytes = new byte[size];
                    System.arraycopy(buffer, 0, readBytes, 0, size);
                    updateView(mDataTurn.ByteArrToHex(readBytes));
                }catch (Exception e){
                    e.printStackTrace();
                    try { Thread.sleep(2000); } catch (InterruptedException ex) { }
                }
            }
        }
    }

    @SuppressLint("HandlerLeak")
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case 0:
                    serialPort.setChecked(false);
                    break;
                case 1:
                    textView.append(msg.obj + "\n");
                    scrollToBottom(textView);
                    break;
                default:
                    break;
            }
        }
    };

    private void updateView(String info){
        Message message = new Message();
        message.what = 1;
        message.obj = info;
        mHandler.sendMessage(message);
    }
    /**
     * 根据scrollView 和子view去测量滑动的位置
     */
    private void scrollToBottom(final View view) {

        mHandler.post(() -> {
            if (mScrollView == null || view == null) return;
            // offset偏移量。是指当textView中内容超出 scrollView的高度，那么超出部分就是偏移量
            int offset = view.getMeasuredHeight() - mScrollView.getMeasuredHeight();
            if (offset < 0) offset = 0;
            //scrollview开始滚动
            mScrollView.scrollTo(0, offset);
        });
    }

    private void close(){
        if (mInputStream != null) {
            try {
                mInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (mOutputStream != null){
            try {
                mOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (mSerialPort != null)
            mSerialPort.close();
    }
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            View v = getCurrentFocus();
            if (isShouldHideInput(v, ev)) {
                InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                if (imm != null) imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
            }
            return super.dispatchTouchEvent(ev);
        }
        // 必不可少，否则所有的组件都不会有TouchEvent了
        if (getWindow().superDispatchTouchEvent(ev)) return true;
        return onTouchEvent(ev);
    }

    public boolean isShouldHideInput(View v, MotionEvent event) {
        if ((v instanceof EditText)) {
            int[] leftTop = {0, 0};
            //获取输入框当前的location位置
            v.getLocationInWindow(leftTop);
            int left = leftTop[0];
            int top = leftTop[1];
            int bottom = top + v.getHeight();
            int right = left + v.getWidth();
            // 点击的是输入框区域，保留点击EditText的事件
            return !(event.getX() > left) || !(event.getX() < right)
                    || !(event.getY() > top) || !(event.getY() < bottom);
        }
        return false;
    }
    @Override
    public void onDestroy() {

        flag = false;
        readThread.interrupt();
        readThread = null;
        close();
        super.onDestroy();
    }
}
